spb/social-runtime-crawler
Public
TypeScript 91.8%
HTML 3.2%
JavaScript 3%
SQL 1.4%
CSS 0.7%
1import { cookies } from "next/headers";2import { NextResponse, type NextRequest } from "next/server";3import { COOKIE, verifyToken } from "@/lib/auth";45export const dynamic = "force-dynamic";6const API_URL = process.env.API_URL ?? "http://127.0.0.1:8350";7const API_TOKEN = process.env.SRC_API_TOKEN ?? "";89/** Authenticated pass-through to the control-plane API (adds the server token, streams SSE as-is). */10async function forward(req: NextRequest, path: string[]) {11 const jar = await cookies();12 if (!verifyToken(jar.get(COOKIE)?.value)) return NextResponse.json({ error: "unauthorized" }, { status: 401 });13 const target = new URL(`/api/${path.join("/")}`, API_URL);14 target.search = req.nextUrl.search;15 const headers: Record<string, string> = { "x-src-token": API_TOKEN };16 if (req.headers.get("content-type")) headers["content-type"] = req.headers.get("content-type")!;17 const upstream = await fetch(target, { method: req.method, headers, body: req.method === "GET" || req.method === "HEAD" ? undefined : await req.text(), cache: "no-store", // @ts-expect-error — undici option for streaming request bodies18 duplex: "half" });19 const ct = upstream.headers.get("content-type") ?? "application/json";20 return new Response(upstream.body, { status: upstream.status, headers: { "content-type": ct, "cache-control": "no-store", ...(ct.includes("event-stream") ? { connection: "keep-alive", "x-accel-buffering": "no" } : {}) } });21}2223export async function GET(req: NextRequest, ctx: { params: Promise<{ path: string[] }> }) {24 return forward(req, (await ctx.params).path);25}26export async function POST(req: NextRequest, ctx: { params: Promise<{ path: string[] }> }) {27 return forward(req, (await ctx.params).path);28}29